home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / xlib04.zip / XRECT.ASM < prev    next >
Assembly Source File  |  1992-11-12  |  22KB  |  539 lines

  1. ;-----------------------------------------------------------------------
  2. ; MODULE XRECT
  3. ;
  4. ; Rectangle functions all MODE X 256 Color resolutions
  5. ;
  6. ; Compile with Tasm.
  7. ; C callable.
  8. ;
  9. ;
  10. ; ****** XLIB - Mode X graphics library                ****************
  11. ; ******                                               ****************
  12. ; ****** Written By Themie Gouthas                     ****************
  13. ;
  14. ; egg@dstos3.dsto.gov.au
  15. ; teg@bart.dsto.gov.au
  16. ;-----------------------------------------------------------------------
  17.  
  18.  
  19. include xlib.inc
  20. include xrect.inc
  21.  
  22.  
  23.     .data
  24. ; Plane masks for clipping left and right edges of rectangle.
  25.         LeftClipPlaneMask       db      00fh,00eh,00ch,008h
  26.     RightClipPlaneMask      db      00fh,001h,003h,007h
  27.     .code
  28.  
  29.  
  30.  
  31. ;---------------------------------------------------------------------------
  32. ; Mode X (320x240, 256 colors) rectangle solid colour fill routine.
  33. ;
  34. ; Based on code originally published in DDJ Mag by M. Abrash
  35. ;
  36. ; with TASM 2. C near-callable as:
  37. ;
  38. ;    void x_rect_fill(int StartX, int StartY, int EndX, int EndY,
  39. ;       unsigned int PageBase, unsigne int color);
  40. ;
  41. ;
  42.  
  43.  
  44. _x_rect_fill proc
  45. ARG     StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Color:word
  46.     push bp              ;preserve caller's stack frame
  47.     mov  bp,sp           ;point to local stack frame
  48.     push si              ;preserve caller's register variables
  49.     push di
  50.  
  51.         cld
  52.     mov  ax,[_ScrnLogicalByteWidth]
  53.     mul  [StartY]            ;offset in page of top rectangle scan line
  54.     mov  di,[StartX]
  55.     shr  di,1                ;X/4 = offset of first rectangle pixel in scan
  56.     shr  di,1                ; line
  57.     add  di,ax               ;offset of first rectangle pixel in page
  58.     add  di,[PageBase]       ;offset of first rectangle pixel in
  59.                      ; display memory
  60.     mov  ax,SCREEN_SEG       ;point ES:DI to the first rectangle
  61.     mov  es,ax               ; pixel's address
  62.     mov  dx,SC_INDEX         ;set the Sequence Controller Index to
  63.     mov  al,MAP_MASK         ; point to the Map Mask register
  64.     out  dx,al
  65.     inc  dx                  ;point DX to the SC Data register
  66.     mov  si,[StartX]
  67.     and  si,0003h                    ;look up left edge plane mask
  68.     mov  bh,LeftClipPlaneMask[si]    ; to clip & put in BH
  69.     mov  si,[EndX]
  70.     and  si,0003h                    ;look up right edge plane
  71.     mov  bl,RightClipPlaneMask[si]   ; mask to clip & put in BL
  72.  
  73.     mov  cx,[EndX]                   ;calculate # of addresses across rect
  74.     mov  si,[StartX]
  75.     cmp  cx,si
  76.     jle  @@FillDone                  ;skip if 0 or negative width
  77.     dec  cx
  78.     and  si,not 011b
  79.     sub  cx,si
  80.     shr  cx,1
  81.     shr  cx,1                 ;# of addresses across rectangle to fill - 1
  82.     jnz  @@MasksSet           ;there's more than one byte to draw
  83.     and  bh,bl                ;there's only one byte, so combine the left
  84.                                   ; and right edge clip masks
  85. @@MasksSet:
  86.     mov  si,[EndY]
  87.     sub  si,[StartY]            ;BX = height of rectangle
  88.     jle  @@FillDone             ;skip if 0 or negative height
  89.     mov  ah,byte ptr [Color]    ;color with which to fill
  90.     mov  bp,[_ScrnLogicalByteWidth]  ;stack frame isn't needed any more
  91.     sub  bp,cx                  ;distance from end of one scan line to start
  92.     dec  bp                     ; of next
  93. @@FillRowsLoop:
  94.     push cx                     ;remember width in addresses - 1
  95.     mov  al,bh                  ;put left-edge clip mask in AL
  96.     out  dx,al                  ;set the left-edge plane (clip) mask
  97.     mov  al,ah                  ;put color in AL
  98.         stosb                       ;draw the left edge
  99.     dec  cx                     ;count off left edge byte
  100.     js   @@FillLoopBottom       ;that's the only byte
  101.     jz   @@DoRightEdge          ;there are only two bytes
  102.     mov  al,00fh                ;middle addresses drawn 4 pixels at a pop
  103.     out  dx,al                  ;set the middle pixel mask to no clip
  104.     mov  al,ah                  ;put color in AL
  105.     rep  stosb                  ;draw middle addresses four pixels apiece
  106. @@DoRightEdge:
  107.     mov  al,bl                  ;put right-edge clip mask in AL
  108.     out  dx,al                  ;set the right-edge plane (clip) mask
  109.     mov  al,ah                  ;put color in AL
  110.         stosb                       ;draw the right edge
  111. @@FillLoopBottom:
  112.     add  di,bp                  ;point to start of the next scan line of
  113.                                     ; the rectangle
  114.     pop  cx                     ;retrieve width in addresses - 1
  115.     dec  si                     ;count down scan lines
  116.     jnz  @@FillRowsLoop
  117. @@FillDone:
  118.     pop  di                     ;restore caller's register variables
  119.     pop  si
  120.     pop  bp                     ;restore caller's stack frame
  121.         ret
  122. _x_rect_fill endp
  123.  
  124. ;---------------------------------------------------------------------------
  125. ; Mode X (320x240, 256 colors) rectangle 4x4 pattern fill routine.
  126. ; Upper left corner of pattern is always aligned to a multiple-of-4
  127. ; row and column. Works on all VGAs. Uses approach of copying the
  128. ; pattern to off-screen display memory, then loading the latches with
  129. ; the pattern for each scan line and filling each scan line four
  130. ; pixels at a time. Fills up to but not including the column at EndX
  131. ; and the row at EndY. No clipping is performed. All ASM code tested
  132. ;
  133. ;
  134. ; Based on code originally published in DDJ Mag by M. Abrash
  135. ;
  136. ;
  137. ;  C near-callable as:
  138. ;
  139. ;    void x_rect_pattern(int StartX, int StartY, int EndX, int EndY,
  140. ;       unsigned int PageBase, char far * Pattern);
  141.  
  142.  
  143.  
  144. _x_rect_pattern proc
  145. ARG     StartX:word,StartY:word,EndX:word,EndY:word,PageBase:word,Pattern:dword
  146. LOCAL   NextScanOffset:word,RectAddrWidth:word,Height:word=LocalStk
  147.     push bp                       ;preserve caller's stack frame
  148.     mov  bp,sp                    ;point to local stack frame
  149.     sub  sp,LocalStk              ;allocate space for local vars
  150.     push si                       ;preserve caller's register variables
  151.     push di
  152.         push ds
  153.         cld
  154.     mov  ax,SCREEN_SEG            ;point ES to display memory
  155.     mov  es,ax
  156.                       ;copy pattern to display memory buffer
  157.     lds  si,dword ptr [Pattern]   ;point to pattern to fill with
  158.     mov  di,PATTERN_BUFFER        ;point ES:DI to pattern buffer
  159.     mov  dx,SC_INDEX              ;point Sequence Controller Index to
  160.     mov  al,MAP_MASK              ; Map Mask
  161.     out  dx,al
  162.     inc  dx                       ;point to SC Data register
  163.     mov  cx,4                     ;4 pixel quadruplets in pattern
  164. @@DownloadPatternLoop:
  165.     mov  al,1                     ;
  166.     out  dx,al                    ;select plane 0 for writes
  167.         movsb                         ;copy over next plane 0 pattern pixel
  168.     dec  di                       ;stay at same address for next plane
  169.     mov  al,2                     ;
  170.     out  dx,al                    ;select plane 1 for writes
  171.         movsb                         ;copy over next plane 1 pattern pixel
  172.     dec  di                       ;stay at same address for next plane
  173.     mov  al,4                     ;
  174.     out  dx,al                    ;select plane 2 for writes
  175.         movsb                         ;copy over next plane 2 pattern pixel
  176.     dec  di                       ;stay at same address for next plane
  177.     mov  al,8                     ;
  178.     out  dx,al                    ;select plane 3 for writes
  179.         movsb                         ;copy over next plane 3 pattern pixel
  180.                                       ; and advance address
  181.         loop @@DownloadPatternLoop
  182.         pop  ds
  183.  
  184.     mov  dx,GC_INDEX              ;set the bit mask to select all bits
  185.     mov  ax,00000h+BIT_MASK       ; from the latches and none from
  186.     out  dx,ax                    ; the CPU, so that we can write the
  187.                                       ; latch contents directly to memory
  188.     mov  ax,[StartY]              ;top rectangle scan line
  189.     mov  si,ax
  190.     and  si,011b                  ;top rect scan line modulo 4
  191.     add  si,PATTERN_BUFFER        ;point to pattern scan line that
  192.                                       ; maps to top line of rect to draw
  193.     mov  dx,[_ScrnLogicalByteWidth]
  194.     mul  dx                       ;offset in page of top rect scan line
  195.     mov  di,[StartX]
  196.     mov  bx,di
  197.     shr  di,1             ;X/4 = offset of first rectangle pixel in scan
  198.     shr  di,1             ; line
  199.     add  di,ax                    ;offset of first rectangle pixel in page
  200.     add  di,[PageBase]            ;offset of first rectangle pixel in
  201.                                       ; display memory
  202.     and  bx,0003h                 ;look up left edge plane mask
  203.     mov  ah,LeftClipPlaneMask[bx] ; to clip
  204.     mov  bx,[EndX]
  205.     and  bx,0003h                  ;look up right edge plane
  206.     mov  al,RightClipPlaneMask[bx] ; mask to clip
  207.     mov  bx,ax                     ;put the masks in BX
  208.  
  209.     mov  cx,[EndX]                 ;calculate # of addresses across rect
  210.     mov  ax,[StartX]
  211.     cmp  cx,ax
  212.     jle  @@FillDone                ;skip if 0 or negative width
  213.     dec  cx
  214.     and  ax,not 011b
  215.     sub  cx,ax
  216.     shr  cx,1
  217.     shr  cx,1                 ;# of addresses across rectangle to fill - 1
  218.     jnz  @@MasksSet           ;there's more than one pixel to draw
  219.     and  bh,bl                ;there's only one pixel, so combine the left
  220.                                   ; and right edge clip masks
  221. @@MasksSet:
  222.     mov  ax,[EndY]
  223.     sub  ax,[StartY]          ;AX = height of rectangle
  224.     jle  @@FillDone           ;skip if 0 or negative height
  225.     mov  [Height],ax
  226.     mov  ax,[_ScrnLogicalByteWidth]
  227.     sub  ax,cx                ;distance from end of one scan line to start
  228.     dec  ax                   ; of next
  229.     mov  [NextScanOffset],ax
  230.     mov  [RectAddrWidth],cx   ;remember width in addresses - 1
  231.     mov  dx,SC_INDEX+1        ;point to Sequence Controller Data reg
  232.                                   ; (SC Index still points to Map Mask)
  233. @@FillRowsLoop:
  234.     mov  cx,[RectAddrWidth]   ;width across - 1
  235.     mov  al,es:[si]           ;read display memory to latch this scan
  236.                                   ; line's pattern
  237.     inc  si                   ;point to the next pattern scan line, wrapping
  238.     jnz  short @@NoWrap       ; back to the start of the pattern if
  239.     sub  si,4                 ; we've run off the end
  240. @@NoWrap:
  241.     mov  al,bh                ;put left-edge clip mask in AL
  242.     out  dx,al                ;set the left-edge plane (clip) mask
  243.         stosb                     ;draw the left edge (pixels come from latches;
  244.                                   ; value written by CPU doesn't matter)
  245.     dec  cx                   ;count off left edge address
  246.     js   @@FillLoopBottom     ;that's the only address
  247.     jz   @@DoRightEdge        ;there are only two addresses
  248.     mov  al,00fh              ;middle addresses drawn 4 pixels at a pop
  249.     out  dx,al                ;set middle pixel mask to no clip
  250.     rep  stosb                ;draw middle addresses four pixels apiece
  251.                                   ; (from latches; value written doesn't matter)
  252. @@DoRightEdge:
  253.     mov  al,bl                ;put right-edge clip mask in AL
  254.     out  dx,al                ;set the right-edge plane (clip) mask
  255.         stosb                     ;draw the right edge (from latches; value
  256.                                   ; written doesn't matter)
  257. @@FillLoopBottom:
  258.     add  di,[NextScanOffset]  ;point to the start of the next scan
  259.                   ; line of the rectangle
  260.     dec  word ptr [Height]    ;count down scan lines
  261.     jnz  @@FillRowsLoop
  262. @@FillDone:
  263.     mov  dx,GC_INDEX+1        ;restore the bit mask to its default,
  264.     mov  al,0ffh              ; which selects all bits from the CPU
  265.     out  dx,al                ; and none from the latches (the GC
  266.                   ; Index still points to Bit Mask)
  267.  
  268.     pop  di                   ;restore caller's register variables
  269.     pop  si
  270.     mov  sp,bp                ;discard storage for local variables
  271.     pop  bp                   ;restore caller's stack frame
  272.         ret
  273. _x_rect_pattern endp
  274.  
  275. ;-----------------------------------------------------------------------
  276. ; Mode X (320x240, 256 colors) display memory to display memory copy
  277. ; routine. Left edge of source rectangle modulo 4 must equal left edge
  278. ; of destination rectangle modulo 4. Works on all VGAs. Uses approach
  279. ; of reading 4 pixels at a time from the source into the latches, then
  280. ; writing the latches to the destination. Copies up to but not
  281. ; including the column at SrcEndX and the row at SrcEndY. No
  282. ; clipping is performed. Results are not guaranteed if the source and
  283. ; destination overlap.
  284. ;
  285. ;
  286. ; Based on code originally published in DDJ Mag by M. Abrash
  287. ;
  288. ;C near-callable as:
  289. ;    void x_cp_vid_rect(int SrcStartX, int SrcStartY,
  290. ;       int SrcEndX, int SrcEndY, int DestStartX,
  291. ;       int DestStartY, unsigned int SrcPageBase,
  292. ;       unsigned int DestPageBase, int SrcBitmapWidth,
  293. ;       int DestBitmapWidth);
  294.  
  295. _x_cp_vid_rect proc
  296.     ARG SrcStartX:word,SrcStartY:word,SrcEndX:word,SrcEndY:word,DestStartX:word,DestStartY:word,SrcPageBase:word,DestPageBase:word,SrcBitmapW:word,DestBitmapW:word
  297.     LOCAL SrcNextOffs:word,DestNextOffs:word,RectAddrW:word,Height:word=LocalStk
  298.     push    bp                  ;preserve caller's stack frame
  299.     mov     bp,sp               ;point to local stack frame
  300.     sub     sp,LocalStk         ;allocate space for local vars
  301.     push    si                  ;preserve caller's register variables
  302.         push    di
  303.         push    ds
  304.  
  305.         cld
  306.     mov     dx,GC_INDEX         ;set the bit mask to select all bits
  307.     mov     ax,00000h+BIT_MASK  ; from the latches and none from
  308.     out dx,ax                   ; the CPU, so that we can write the
  309.                     ; latch contents directly to memory
  310.     mov     ax,SCREEN_SEG       ;point ES to display memory
  311.         mov     es,ax
  312.     mov     ax,[DestBitmapW]
  313.     shr     ax,2                ;convert to width in addresses
  314.     mul     [DestStartY]        ;top dest rect scan line
  315.     mov     di,[DestStartX]
  316.     shr     di,2                ;X/4 = offset of first dest rect pixel in
  317.                     ; scan line
  318.     add     di,ax               ;offset of first dest rect pixel in page
  319.     add     di,[DestPageBase]   ;offset of first dest rect pixel
  320.                     ; in display memory
  321.     mov     ax,[SrcBitmapW]
  322.     shr     ax,2                ;convert to width in addresses
  323.     mul     [SrcStartY]      ;top source rect scan line
  324.     mov     si,[SrcStartX]
  325.         mov     bx,si
  326.     shr     si,2              ;X/4 = offset of first source rect pixel in
  327.                   ; scan line
  328.     add     si,ax             ;offset of first source rect pixel in page
  329.     add     si,[SrcPageBase]  ;offset of first source rect
  330.                   ; pixel in display memory
  331.     and     bx,0003h                     ;look up left edge plane mask
  332.     mov     ah,LeftClipPlaneMask[bx]  ; to clip
  333.     mov     bx,[SrcEndX]
  334.     and     bx,0003h                     ;look up right edge plane
  335.     mov     al,RightClipPlaneMask[bx] ; mask to clip
  336.     mov     bx,ax                        ;put the masks in BX
  337.  
  338.     mov     cx,[SrcEndX]              ;calculate # of addresses across
  339.     mov     ax,[SrcStartX]            ; rect
  340.         cmp     cx,ax
  341.     jle     @@CopyDone                   ;skip if 0 or negative width
  342.         dec     cx
  343.         and     ax,not 011b
  344.         sub     cx,ax
  345.     shr     cx,2             ;# of addresses across rectangle to copy - 1
  346.     jnz     @@MasksSet       ;there's more than one address to draw
  347.     and     bh,bl            ;there's only one address, so combine the left
  348.                  ; and right edge clip masks
  349. @@MasksSet:
  350.     mov     ax,[SrcEndY]
  351.     sub     ax,[SrcStartY]     ;AX = height of rectangle
  352.     jle     @@CopyDone         ;skip if 0 or negative height
  353.     mov     [Height],ax
  354.     mov     ax,[DestBitmapW]
  355.     shr     ax,2               ;convert to width in addresses
  356.     sub     ax,cx              ;distance from end of one dest scan line
  357.     dec     ax                 ; to start of next
  358.     mov     [DestNextOffs],ax
  359.     mov     ax,[SrcBitmapW]
  360.     shr     ax,2               ;convert to width in addresses
  361.     sub     ax,cx              ;distance from end of one source scan line
  362.     dec     ax                 ; to start of next
  363.     mov     [SrcNextOffs],ax
  364.     mov     [RectAddrW],cx     ;remember width in addresses - 1
  365.     mov     dx,SC_INDEX+1      ;point to Sequence Controller Data reg
  366.                    ; (SC Index still points to Map Mask)
  367.     mov     ax,es              ;DS=ES=screen segment for MOVS
  368.         mov     ds,ax
  369. @@CopyRowsLoop:
  370.     mov     cx,[RectAddrW]     ;width across - 1
  371.     mov     al,bh              ;put left-edge clip mask in AL
  372.     out     dx,al              ;set the left-edge plane (clip) mask
  373.     movsb                      ;copy the left edge (pixels go through
  374.                    ; latches)
  375.     dec     cx                 ;count off left edge address
  376.     js      @@CopyLoopBottom   ;that's the only address
  377.     jz      @@DoRightEdge      ;there are only two addresses
  378.     mov     al,00fh            ;middle addresses are drawn 4 pix per go
  379.     out     dx,al              ;set the middle pixel mask to no clip
  380.     rep     movsb              ;draw the middle addresses four pix per go
  381.                    ; (pixels copied through latches)
  382. @@DoRightEdge:
  383.         mov     al,bl   ;put right-edge clip mask in AL
  384.         out     dx,al   ;set the right-edge plane (clip) mask
  385.         movsb           ;draw the right edge (pixels copied through
  386.                         ; latches)
  387. @@CopyLoopBottom:
  388.     add     si,[SrcNextOffs]   ;point to the start of
  389.     add     di,[DestNextOffs]  ; next source & dest lines
  390.     dec     word ptr [Height]  ;count down scan lines
  391.     jnz     @@CopyRowsLoop
  392. @@CopyDone:
  393.     mov     dx,GC_INDEX+1   ;restore the bit mask to its default,
  394.         mov     al,0ffh         ; which selects all bits from the CPU
  395.         out     dx,al           ; and none from the latches (the GC
  396.                                 ; Index still points to Bit Mask)
  397.         pop     ds
  398.     pop     di              ;restore caller's register variables
  399.         pop     si
  400.     mov     sp,bp           ;discard storage for local variables
  401.     pop     bp              ;restore caller's stack frame
  402.         ret
  403. _x_cp_vid_rect  endp
  404.  
  405. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  406. ; Copy a rectangular region of a VGA screen, with x coordinates
  407. ; rounded to the nearest byte -- source and destination may overlap.
  408. ;
  409. ; C near-callable as:
  410. ;
  411. ; void x_shift_rect (WORD SrcLeft, WORD SrcTop,
  412. ;                    WORD SrcRight, WORD SrcBottom,
  413. ;                    WORD DestLeft, WORD DestTop, WORD ScreenOffs);
  414. ;
  415. ; SrcRight is rounded up, and the left edges are rounded down, to ensure
  416. ; that the pixels pointed to by the arguments are inside the rectangle.
  417. ;
  418. ; The width of the rectangle in bytes (width in pixels / 4)
  419. ; cannot exceed 255.
  420. ;
  421. ; ax, bx, cx, dx, and es eat hot lead.
  422. ;
  423. ; This function was written by Matthew MacKenzie
  424. ; matm@eng.umd.edu
  425.  
  426.     align   2
  427. _x_shift_rect proc
  428. ARG     SrcLeft,SrcTop,SrcRight,SrcBottom,DestLeft,DestTop,ScreenOffs:word
  429. LOCAL   width_temp:word=LocalStk
  430.  
  431.     push bp
  432.     mov bp, sp
  433.     sub sp, LocalStk
  434.     push si
  435.     push di
  436.     push ds
  437.  
  438. ; find values for width & x motion
  439.     mov si, SrcLeft     ; source x in bytes
  440.     shr si, 2
  441.  
  442.     mov di, DestLeft    ; destination x in bytes
  443.     shr di, 2
  444.  
  445.     mov bx, SrcRight    ; right edge of source in bytes, rounded up
  446.     add bx, 3
  447.     shr bx, 2
  448.     sub bx, si
  449.     mov ax, bx          ; width - 1
  450.     inc bx              ; we'll use this as an offset for moving up or down
  451.     mov width_temp, bx
  452.  
  453.     cld                 ; by default, strings increment
  454.  
  455.     cmp si, di
  456.     jge @@MovingLeft
  457.  
  458. ; we're moving our rectangle right, so we copy it from right to left
  459.     add si, ax          ; source & destination will start on the right edge
  460.     add di, ax
  461.     neg bx
  462.     std                 ; strings decrement
  463.  
  464. @@MovingLeft:
  465.  
  466. ; find values for height & y motion
  467.     mov cx, _ScrnLogicalByteWidth ; bytes to move to advance one line
  468.     mov ax, SrcTop
  469.     mov dx, DestTop     ; default destination y
  470.     cmp ax, dx
  471.     jge @@MovingUp
  472.  
  473. ; we're moving our rectangle down, so we copy it from bottom to top
  474.     mov ax, SrcBottom   ; source starts at bottom
  475.     add dx, ax          ; add (height - 1) to destination y
  476.     sub dx, SrcTop
  477.     neg cx              ; advance up screen rather than down
  478.  
  479. @@MovingUp:
  480.     push dx             ; save destination y during multiply
  481.     mul _ScrnLogicalByteWidth
  482.     add si, ax          ; add y in bytes to source
  483.     pop ax              ; restore destination y
  484.     mul _ScrnLogicalByteWidth
  485.     add di, ax          ; add y in bytes to destination
  486.  
  487.     sub cx, bx          ; final value for moving up or down
  488.  
  489.     add si, ScreenOffs  ; source & destination are on the same screen
  490.     add di, ScreenOffs
  491.  
  492.     mov dx, SC_INDEX    ; set map mask to all four planes
  493.     mov ax, 00f02h
  494.     out dx, ax
  495.  
  496.     mov dx, GC_INDEX    ; set bit mask to take data from latches
  497.     mov ax, BIT_MASK    ;  rather than CPU
  498.     out dx, ax
  499.  
  500.     mov ax, SCREEN_SEG  ; source and destination are VGA memory
  501.     mov es, ax
  502.     mov ds, ax
  503.  
  504.     mov ah, byte ptr width_temp ; width in bytes should fit in 8 bits
  505.  
  506.     mov bx, SrcBottom   ; height - 1
  507.     sub bx, SrcTop
  508.  
  509.     mov dx, cx          ; bytes to add to advance one line
  510.  
  511.     xor ch, ch          ; ready to rock
  512.  
  513. @@LineLoop:
  514.     mov cl, ah          ; load width in bytes
  515.     rep movsb           ; move 4 pixels at a time using latches (YOW!)
  516.  
  517.     add si, dx          ; advance source by one line
  518.     add di, dx          ; advance destination by one line
  519.  
  520.     dec bx              ; line counter
  521.     jge @@LineLoop      ; 0 still means one more to go
  522.  
  523.     mov dx, GC_INDEX + 1; set bit mask to take data from CPU (normal setting)
  524.     mov al, 0ffh
  525.     out dx, al
  526.  
  527. ; kick
  528.     pop ds
  529.     pop di
  530.     pop si
  531.     mov sp, bp
  532.     pop bp
  533.  
  534.     ret
  535. _x_shift_rect endp
  536.  
  537.     end
  538.  
  539.